home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / ed.screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-25  |  28.8 KB  |  1,269 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/ed.screen.c,v 3.3 1991/07/18 18:00:02 christos Exp $ */
  2. /*
  3.  * ed.screen.c: Editor/termcap-curses interface
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "config.h"
  38. RCSID("$Id: ed.screen.c,v 3.3 1991/07/18 18:00:02 christos Exp $")
  39.  
  40. #include "sh.h"
  41. #include "ed.h"
  42. #include "tc.h"
  43. #include "ed.defns.h"
  44.  
  45. /*
  46.  * We don't prototype these, cause some systems have them wrong!
  47.  */
  48. extern char *tgoto();
  49. extern char *tgetstr();
  50. extern char *tputs();
  51. extern int tgetent();
  52. extern int tgetflag();
  53. extern int tgetnum();
  54.  
  55.  
  56. /* #define DEBUG_LITERAL */
  57.  
  58. /*
  59.  * IMPORTANT NOTE: these routines are allowed to look at the current screen
  60.  * and the current possition assuming that it is correct.  If this is not
  61.  * true, then the update will be WRONG!  This is (should be) a valid
  62.  * assumption...
  63.  */
  64.  
  65. #define TC_BUFSIZ 2048
  66.  
  67. #define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0')
  68. #define Str(a) tstr[a].str
  69. #define Val(a) tval[a].val
  70.  
  71. static struct {
  72.     char   *b_name;
  73.     int     b_rate;
  74. }       baud_rate[] = {
  75.  
  76. #ifdef B0
  77.     { "0", B0 },
  78. #endif
  79. #ifdef B50
  80.     { "50", B50 },
  81. #endif
  82. #ifdef B75
  83.     { "75", B75 },
  84. #endif
  85. #ifdef B110
  86.     { "110", B110 },
  87. #endif
  88. #ifdef B134
  89.     { "134", B134 },
  90. #endif
  91. #ifdef B150
  92.     { "150", B150 },
  93. #endif
  94. #ifdef B200
  95.     { "200", B200 },
  96. #endif
  97. #ifdef B300
  98.     { "300", B300 },
  99. #endif
  100. #ifdef B600
  101.     { "600", B600 },
  102. #endif
  103. #ifdef B900
  104.     { "900", B900 },
  105. #endif
  106. #ifdef B1200
  107.     { "1200", B1200 },
  108. #endif
  109. #ifdef B1800
  110.     { "1800", B1800 },
  111. #endif
  112. #ifdef B2400
  113.     { "2400", B2400 },
  114. #endif
  115. #ifdef B3600
  116.     { "3600", B3600 },
  117. #endif
  118. #ifdef B4800
  119.     { "4800", B4800 },
  120. #endif
  121. #ifdef B7200
  122.     { "7200", B7200 },
  123. #endif
  124. #ifdef B9600
  125.     { "9600", B9600 },
  126. #endif
  127. #ifdef EXTA
  128.     { "19200", EXTA },
  129. #endif
  130. #ifdef B19200
  131.     { "19200", B19200 },
  132. #endif
  133. #ifdef EXTB
  134.     { "38400", EXTB },
  135. #endif
  136. #ifdef B38400
  137.     { "38400", B38400 },
  138. #endif
  139.     { NULL, 0 }
  140. };
  141.  
  142. static struct termcapstr {
  143.     char   *name;
  144.     char   *long_name;
  145.     char   *str;
  146. }       tstr[] = {
  147.  
  148. #define T_al    0
  149.     {    "al",    "add new blank line",        NULL },
  150. #define T_bl    1
  151.     {    "bl",    "audible bell",            NULL },
  152. #define T_cd    2
  153.     {    "cd",    "clear to bottom",        NULL },
  154. #define T_ce    3
  155.     {    "ce",    "clear to end of line",        NULL },
  156. #define T_ch    4
  157.     {    "ch",    "cursor to horiz pos",        NULL },
  158. #define T_cl    5
  159.     {    "cl",    "clear screen",            NULL },
  160. #define    T_dc    6
  161.     {    "dc",    "delete a character",        NULL },
  162. #define    T_dl    7
  163.     {    "dl",    "delete a line",        NULL },
  164. #define    T_dm    8
  165.     {    "dm",    "start delete mode",        NULL },
  166. #define    T_ed    9
  167.     {    "ed",    "end delete mode",        NULL },
  168. #define    T_ei    10
  169.     {    "ei",    "end insert mode",        NULL },
  170. #define    T_fs    11
  171.     {    "fs",    "cursor from status line",    NULL },
  172. #define    T_ho    12
  173.     {    "ho",    "home cursor",            NULL },
  174. #define    T_ic    13
  175.     {    "ic",    "insert character",        NULL },
  176. #define    T_im    14 
  177.     {    "im",    "start insert mode",        NULL },
  178. #define    T_ip    15
  179.     {    "ip",    "insert padding",        NULL },
  180. #define    T_kd    16
  181.     {    "kd",    "sends cursor down",        NULL },
  182. #define    T_kl    17
  183.     {    "kl",    "sends cursor left",        NULL },
  184. #define T_kr    18
  185.     {    "kr",    "sends cursor right",        NULL },
  186. #define T_ku    19
  187.     {    "ku",    "sends cursor up",        NULL },
  188. #define T_md    20
  189.     {    "md",    "begin bold",            NULL },
  190. #define T_me    21
  191.     {    "me",    "end attributes",        NULL },
  192. #define T_nd    22
  193.     {    "nd",    "non destructive space",    NULL },
  194. #define T_se    23
  195.     {    "se",    "end standout",            NULL },
  196. #define T_so    24
  197.     {    "so",    "begin standout",        NULL },
  198. #define T_ts    25
  199.     {    "ts",    "cursor to status line",    NULL },
  200. #define T_up    26
  201.     {    "up",    "cursor up one",        NULL },
  202. #define T_us    27
  203.     {    "us",    "begin underline",        NULL },
  204. #define T_ue    28
  205.     {    "ue",    "end underline",        NULL },
  206. #define T_vb    29
  207.     {    "vb",    "visible bell",            NULL },
  208. #define T_DC    30
  209.     {    "DC",    "delete multiple chars",    NULL },
  210. #define T_DO    31
  211.     {    "DO",    "cursor down multiple",        NULL },
  212. #define T_IC    32
  213.     {    "IC",    "insert multiple chars",    NULL },
  214. #define T_LE    33
  215.     {    "LE",    "cursor left multiple",        NULL },
  216. #define T_RI    34
  217.     {    "RI",    "cursor right multiple",    NULL },
  218. #define T_UP    35
  219.     {    "UP",    "cursor up multiple",        NULL },
  220. #define T_str    36
  221.     {    NULL,    NULL,        NULL }
  222. };
  223.  
  224. static struct termcapval {
  225.     char   *name;
  226.     char   *long_name;
  227.     int     val;
  228. }       tval[] = {
  229. #define T_pt    0
  230.     {    "pt",    "can use physical tabs", 0 },
  231. #define T_li    1
  232.     {    "li",    "Number of lines",     0 },
  233. #define T_co    2
  234.     {    "co",    "Number of columns",     0 },
  235. #define T_km    3
  236.     {    "km",    "Has meta key",         0 },
  237. #define T_val    4
  238.     {    NULL, NULL,         0 }
  239. };
  240.  
  241. static bool me_all = 0;        /* does two or more of the attributes use me */
  242.  
  243. static    void    ReBufferDisplay    __P((void));
  244. static    void    TCalloc        __P((struct termcapstr *, char *)); 
  245.  
  246.  
  247. static void
  248. TCalloc(t, cap)
  249.     struct termcapstr *t;
  250.     char   *cap;
  251. {
  252.     static char termcap_alloc[TC_BUFSIZ];
  253.     char    termbuf[TC_BUFSIZ];
  254.     struct termcapstr *ts;
  255.     static int tloc = 0;
  256.     int     tlen, clen;
  257.  
  258.     if (cap == NULL || *cap == '\0') {
  259.     t->str = NULL;
  260.     return;
  261.     }
  262.     else
  263.     clen = strlen(cap);
  264.  
  265.     if (t->str == NULL)
  266.     tlen = 0;
  267.     else
  268.     tlen = strlen(t->str);
  269.  
  270.     /*
  271.      * New string is shorter; no need to allocate space
  272.      */
  273.     if (clen <= tlen) {
  274.     (void) strcpy(t->str, cap);
  275.     return;
  276.     }
  277.  
  278.     /*
  279.      * New string is longer; see if we have enough space to append
  280.      */
  281.     if (tloc + 3 < TC_BUFSIZ) {
  282.     (void) strcpy(t->str = &termcap_alloc[tloc], cap);
  283.     tloc += clen + 1;    /* one for \0 */
  284.     return;
  285.     }
  286.  
  287.     /*
  288.      * Compact our buffer; no need to check compaction, cause we know it
  289.      * fits...
  290.      */
  291.     tlen = 0;
  292.     for (ts = tstr; ts->name != NULL; ts++)
  293.     if (t != ts && ts->str != NULL && ts->str[0] != '\0') {
  294.         char   *ptr;
  295.  
  296.         for (ptr = ts->str; *ptr != '\0'; termbuf[tlen++] = *ptr++);
  297.         termbuf[tlen++] = '\0';
  298.     }
  299.     copy(termcap_alloc, termbuf, TC_BUFSIZ);
  300.     tloc = tlen;
  301.     if (tloc + 3 >= TC_BUFSIZ) {
  302.     stderror(ERR_NAME | ERR_TCNOSTR);
  303.     return;
  304.     }
  305.     (void) strcpy(t->str = &termcap_alloc[tloc], cap);
  306.     tloc += clen + 1;        /* one for \0 */
  307.     return;
  308. }
  309.  
  310.  
  311. /*ARGSUSED*/
  312. void
  313. TellTC(what)
  314.     char   *what;
  315. {
  316.     struct termcapstr *t;
  317.  
  318.     xprintf("\n\tTcsh thinks your terminal has the\n");
  319.     xprintf("\tfollowing characteristics:\n\n");
  320.     xprintf("\tIt has %d columns and %d lines\n",
  321.         Val(T_co), Val(T_li));
  322.     xprintf("\tIt has %s meta key\n", T_HasMeta ? "a" : "no");
  323.     xprintf("\tIt can%suse tabs\n", T_Tabs ? " " : "not ");
  324.  
  325.     for (t = tstr; t->name != NULL; t++)
  326.     xprintf("\t%25s (%s) == %s\n", t->long_name, t->name,
  327.         t->str && *t->str ? t->str : "(empty)");
  328.     xprintf("\n");
  329. }
  330.  
  331.  
  332. static void
  333. ReBufferDisplay()
  334. {
  335.     register int i;
  336.     Char  **b;
  337.     Char  **bufp;
  338.  
  339.     b = Display;
  340.     Display = NULL;
  341.     if (b != NULL) {
  342.     for (bufp = b; *bufp != NULL; bufp++)
  343.         xfree((ptr_t) * bufp);
  344.     xfree((ptr_t) b);
  345.     }
  346.     b = Vdisplay;
  347.     Vdisplay = NULL;
  348.     if (b != NULL) {
  349.     for (bufp = b; *bufp != NULL; bufp++)
  350.         xfree((ptr_t) * bufp);
  351.     xfree((ptr_t) b);
  352.     }
  353.     /* make this public, -1 to avoid wraps */
  354.     TermH = Val(T_co) - 1;
  355.     TermV = (INBUFSIZ * 4) / TermH + 1;
  356.     b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1)));
  357.     for (i = 0; i < TermV; i++)
  358.     b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1)));
  359.     b[TermV] = NULL;
  360.     Display = b;
  361.     b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1)));
  362.     for (i = 0; i < TermV; i++)
  363.     b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1)));
  364.     b[TermV] = NULL;
  365.     Vdisplay = b;
  366. }
  367.  
  368. void
  369. SetTC(what, how)
  370.     char   *what, *how;
  371. {
  372.     struct termcapstr *ts;
  373.     struct termcapval *tv;
  374.  
  375.     /*
  376.      * Do the strings first
  377.      */
  378.     setname("settc");
  379.     for (ts = tstr; ts->name != NULL; ts++)
  380.     if (strcmp(ts->name, what) == 0)
  381.         break;
  382.     if (ts->name != NULL) {
  383.     TCalloc(ts, how);
  384.     /*
  385.      * Reset variables
  386.      */
  387.     if (GoodStr(T_me) && GoodStr(T_ue))
  388.         me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
  389.     else
  390.         me_all = 0;
  391.     if (GoodStr(T_me) && GoodStr(T_se))
  392.         me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
  393.  
  394.     T_CanCEOL = GoodStr(T_ce);
  395.     T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
  396.     T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
  397.     T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
  398.     return;
  399.     }
  400.  
  401.     /*
  402.      * Do the numeric ones second
  403.      */
  404.     for (tv = tval; tv->name != NULL; tv++)
  405.     if (strcmp(tv->name, what) == 0)
  406.         break;
  407.  
  408.     if (tv->name != NULL) {
  409.     if (tv == &tval[T_pt] || tv == &tval[T_km]) {
  410.         if (strcmp(how, "yes") == 0)
  411.         tv->val = 1;
  412.         else if (strcmp(how, "no") == 0)
  413.         tv->val = 0;
  414.         else {
  415.         stderror(ERR_SETTCUS, tv->name);
  416.         return;
  417.         }
  418.         T_Tabs = Val(T_pt);
  419.         T_HasMeta = Val(T_km);
  420.         return;
  421.     }
  422.     else {
  423.         tv->val = atoi(how);
  424.         T_Cols = Val(T_co);
  425.         T_Lines = Val(T_li);
  426.         if (tv == &tval[T_co] || tv == &tval[T_li])
  427.         ChangeSize(Val(T_li), Val(T_co));
  428.         return;
  429.     }
  430.     }
  431.     stderror(ERR_NAME | ERR_TCCAP, what);
  432.     return;
  433. }
  434.  
  435.  
  436. /*
  437.  * Print the termcap string out with variable substitution
  438.  */
  439. void
  440. EchoTC(v)
  441.     Char  **v;
  442. {
  443.     char   *cap, *scap, cv[BUFSIZ];
  444.     int     arg_need, arg_cols, arg_rows;
  445.     int     verbose = 0, silent = 0;
  446.     char   *area;
  447.     static char *fmts = "%s\n", *fmtd = "%d\n";
  448.     char    buf[TC_BUFSIZ];
  449.  
  450.     area = buf;
  451.  
  452.     setname("echotc");
  453.  
  454.     tglob(v);
  455.     if (gflag) {
  456.     v = globall(v);
  457.     if (v == 0)
  458.         stderror(ERR_NAME | ERR_NOMATCH);
  459.     }
  460.     else
  461.     v = gargv = saveblk(v);
  462.     trim(v);
  463.  
  464.     if (!*v || *v[0] == '\0')
  465.     return;
  466.     if (v[0][0] == '-') {
  467.     switch (v[0][1]) {
  468.     case 'v':
  469.         verbose = 1;
  470.         break;
  471.     case 's':
  472.         silent = 1;
  473.         break;
  474.     default:
  475.         stderror(ERR_NAME | ERR_TCUSAGE);
  476.         break;
  477.     }
  478.     v++;
  479.     }
  480.     (void) strcpy(cv, short2str(*v));
  481.     if (strcmp(cv, "tabs") == 0) {
  482.     xprintf(fmts, T_Tabs ? "yes" : "no");
  483.     flush();
  484.     return;
  485.     }
  486.     else if (strcmp(cv, "meta") == 0) {
  487.     xprintf(fmts, Val(T_km) ? "yes" : "no");
  488.     flush();
  489.     return;
  490.     }
  491.     else if (strcmp(cv, "baud") == 0) {
  492.     int     i;
  493.  
  494.     for (i = 0; baud_rate[i].b_name != NULL; i++)
  495.         if (T_Speed == baud_rate[i].b_rate) {
  496.         xprintf(fmts, baud_rate[i].b_name);
  497.         flush();
  498.         return;
  499.         }
  500.     xprintf(fmtd, 0);
  501.     flush();
  502.     return;
  503.     }
  504.     else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0) {
  505.     xprintf(fmtd, Val(T_li));
  506.     flush();
  507.     return;
  508.     }
  509.     else if (strcmp(cv, "cols") == 0) {
  510.     xprintf(fmtd, Val(T_co));
  511.     flush();
  512.     return;
  513.     }
  514.  
  515.     /*
  516.      * Count home many values we need for this capability.
  517.      */
  518.     scap = tgetstr(cv, &area);
  519.     if (!scap || scap[0] == '\0')
  520.     stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCCAP), cv);
  521.  
  522.     for (cap = scap, arg_need = 0; *cap; cap++)
  523.     if (*cap == '%')
  524.         switch (*++cap) {
  525.         case 'd':
  526.         case '2':
  527.         case '3':
  528.         case '.':
  529.         case '+':
  530.         arg_need++;
  531.         break;
  532.         case '%':
  533.         case '>':
  534.         case 'i':
  535.         case 'r':
  536.         case 'n':
  537.         case 'B':
  538.         case 'D':
  539.         break;
  540.         default:
  541.         /*
  542.          * hpux has lot's of them...
  543.          */
  544.         if (verbose)
  545.             stderror(ERR_NAME | ERR_TCPARM, *cap);
  546.         /* This is bad, but I won't complain */
  547.         break;
  548.         }
  549.  
  550.     switch (arg_need) {
  551.     case 0:
  552.     v++;
  553.     if (*v && *v[0])
  554.         stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCARGS), 
  555.              cv, arg_need);
  556.     (void) tputs(scap, 1, putraw);
  557.     break;
  558.     case 1:
  559.     v++;
  560.     if (!*v || *v[0] == '\0')
  561.         stderror(ERR_NAME | ERR_TCNARGS, cv, 1);
  562.     arg_rows = 0;
  563.     arg_cols = atoi(short2str(*v));
  564.     v++;
  565.     if (*v && *v[0])
  566.         stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCARGS), 
  567.              cv, arg_need);
  568.     (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, putraw);
  569.     break;
  570.     default:
  571.     /* This is wrong, but I will ignore it... */
  572.     if (verbose)
  573.         stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
  574.     case 2:
  575.     v++;
  576.     if (!*v || *v[0] == '\0')
  577.         stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCNARGS), cv, 2);
  578.     arg_cols = atoi(short2str(*v));
  579.     v++;
  580.     if (!*v || *v[0] == '\0')
  581.         stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCNARGS), cv, 2);
  582.     arg_rows = atoi(short2str(*v));
  583.     v++;
  584.     if (*v && *v[0])
  585.         stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCARGS), 
  586.              cv, arg_need);
  587.     (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, putraw);
  588.     break;
  589.     }
  590.     flush();
  591.     if (gargv) {
  592.     blkfree(gargv);
  593.     gargv = 0;
  594.     }
  595. }
  596.  
  597. bool    GotTermCaps = 0;
  598.  
  599. void
  600. BindArrowKeys()
  601. {
  602.     KEYCMD *map;
  603.     int     i;
  604.     char   *p;
  605.     static struct {
  606.     int     key, fun;
  607.     }       ar[] =
  608.     {
  609.     { T_kd, F_DOWN_HIST },
  610.     { T_ku, F_UP_HIST   },
  611.     { T_kl, F_CHARBACK  },
  612.     { T_kr, F_CHARFWD   }
  613.     };
  614.  
  615.     if (!GotTermCaps)
  616.     return;
  617.     map = VImode ? CcAltMap : CcKeyMap;
  618.  
  619.     for (i = 0; i < 4; i++) {
  620.     p = tstr[ar[i].key].str;
  621.     if (p && *p) {
  622.         if (p[1]) {
  623.         AddXkeyCmd(str2short(p), ar[i].fun);
  624.         map[(unsigned char) *p] = F_XKEY;
  625.         }
  626.         else if (map[(unsigned char) *p] == F_UNASSIGNED) {
  627.         ClearXkey(map, str2short(p));
  628.         map[(unsigned char) *p] = ar[i].fun;
  629.         }
  630.     }
  631.     }
  632. }
  633.  
  634. static Char cur_atr = 0;    /* current attributes */
  635.  
  636. void
  637. SetAttributes(atr)
  638.     int     atr;
  639. {
  640.     atr &= ATTRIBUTES;
  641.     if (atr != cur_atr) {
  642.     if (me_all && GoodStr(T_me)) {
  643.         if ((cur_atr & BOLD) && !(atr & BOLD) ||
  644.         (cur_atr & UNDER) && !(atr & UNDER) ||
  645.         (cur_atr & STANDOUT) && !(atr & STANDOUT)) {
  646.         (void) tputs(Str(T_me), 1, putpure);
  647.         cur_atr = 0;
  648.         }
  649.     }
  650.     if ((atr & BOLD) != (cur_atr & BOLD)) {
  651.         if (atr & BOLD) {
  652.         if (GoodStr(T_md) && GoodStr(T_me)) {
  653.             (void) tputs(Str(T_md), 1, putpure);
  654.             cur_atr |= BOLD;
  655.         }
  656.         }
  657.         else {
  658.         if (GoodStr(T_md) && GoodStr(T_me)) {
  659.             (void) tputs(Str(T_me), 1, putpure);
  660.             if ((cur_atr & STANDOUT) && GoodStr(T_se)) {
  661.             (void) tputs(Str(T_se), 1, putpure);
  662.             cur_atr &= ~STANDOUT;
  663.             }
  664.             if ((cur_atr & UNDER) && GoodStr(T_ue)) {
  665.             (void) tputs(Str(T_ue), 1, putpure);
  666.             cur_atr &= ~UNDER;
  667.             }
  668.             cur_atr &= ~BOLD;
  669.         }
  670.         }
  671.     }
  672.     if ((atr & STANDOUT) != (cur_atr & STANDOUT)) {
  673.         if (atr & STANDOUT) {
  674.         if (GoodStr(T_so) && GoodStr(T_se)) {
  675.             (void) tputs(Str(T_so), 1, putpure);
  676.             cur_atr |= STANDOUT;
  677.         }
  678.         }
  679.         else {
  680.         if (GoodStr(T_se)) {
  681.             (void) tputs(Str(T_se), 1, putpure);
  682.             cur_atr &= ~STANDOUT;
  683.         }
  684.         }
  685.     }
  686.     if ((atr & UNDER) != (cur_atr & UNDER)) {
  687.         if (atr & UNDER) {
  688.         if (GoodStr(T_us) && GoodStr(T_ue)) {
  689.             (void) tputs(Str(T_us), 1, putpure);
  690.             cur_atr |= UNDER;
  691.         }
  692.         }
  693.         else {
  694.         if (GoodStr(T_ue)) {
  695.             (void) tputs(Str(T_ue), 1, putpure);
  696.             cur_atr &= ~UNDER;
  697.         }
  698.         }
  699.     }
  700.     }
  701. }
  702.  
  703. /* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */
  704. int
  705. CanWeTab()
  706. {
  707.     return (Val(T_pt));
  708. }
  709.  
  710. void
  711. MoveToLine(where)        /* move to line <where> (first line == 0) */
  712.     int     where;        /* as efficiently as possible; */
  713. {
  714.     int     del, i;
  715.  
  716.     if (where == CursorV)
  717.     return;
  718.  
  719.     if (where > TermV) {
  720. #ifdef DEBUG_SCREEN
  721.     xprintf("MoveToLine: where is ridiculous: %d\r\n", where);
  722.     flush();
  723. #endif /* DEBUG_SCREEN */
  724.     return;
  725.     }
  726.  
  727.     if ((del = where - CursorV) > 0) {
  728.     if ((del > 1) && GoodStr(T_DO))
  729.         (void) tputs(tgoto(Str(T_DO), del, del), del, putpure);
  730.     else {
  731.         for (i = 0; i < del; i++)
  732.         (void) putraw('\n');
  733.         CursorH = 0;    /* because the \n will become \r\n */
  734.     }
  735.     }
  736.     else {            /* del < 0 */
  737.     if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
  738.         (void) tputs(tgoto(Str(T_UP), -del, -del), -del, putpure);
  739.     else {
  740.         if (GoodStr(T_up))
  741.         for (i = 0; i < -del; i++)
  742.             (void) tputs(Str(T_up), 1, putpure);
  743.     }
  744.     }
  745.     CursorV = where;        /* now where is here */
  746. }
  747.  
  748. void
  749. MoveToChar(where)        /* move to character position (where) */
  750.     int     where;
  751. {                /* as efficiently as possible */
  752.     int     del, i;
  753.  
  754. mc_again:
  755.     if (where == CursorH)
  756.     return;
  757.  
  758.     if (where > (TermH + 1)) {
  759. #ifdef DEBUG_SCREEN
  760.     xprintf("MoveToChar: where is riduculous: %d\r\n", where);
  761.     flush();
  762. #endif /* DEBUG_SCREEN */
  763.     return;
  764.     }
  765.  
  766.     if (!where) {        /* if where is first column */
  767.     (void) putraw('\r');    /* do a CR */
  768.     CursorH = 0;
  769.     return;
  770.     }
  771.  
  772.     del = where - CursorH;
  773.  
  774.     if ((del < -4 || del > 4) && GoodStr(T_ch))
  775.     /* go there directly */
  776.     (void) tputs(tgoto(Str(T_ch), where, where), where, putpure);
  777.     else {
  778.     if (del > 0) {        /* moving forward */
  779.         if ((del > 4) && GoodStr(T_RI))
  780.         (void) tputs(tgoto(Str(T_RI), del, del), del, putpure);
  781.         else {
  782.         if (T_Tabs) {    /* if I can do tabs, use them */
  783.             if ((CursorH & 0370) != (where & 0370)) {
  784.             /* if not within tab stop */
  785.             for (i = (CursorH & 0370); i < (where & 0370); i += 8)
  786.                 (void) putraw('\t');    /* then tab over */
  787.             CursorH = where & 0370;
  788.             }
  789.         }
  790.         /* it's usually cheaper to just write the chars, so we do. */
  791.  
  792.         /* NOTE THAT so_write() WILL CHANGE CursorH!!! */
  793.         so_write(&Display[CursorV][CursorH], where - CursorH);
  794.  
  795.         }
  796.     }
  797.     else {            /* del < 0 := moving backward */
  798.         if ((-del > 4) && GoodStr(T_LE))
  799.         (void) tputs(tgoto(Str(T_LE), -del, -del), -del, putpure);
  800.         else {        /* can't go directly there */
  801.         /* if the "cost" is greater than the "cost" from col 0 */
  802.         if (T_Tabs ? (-del > ((where >> 3) + (where & 07)))
  803.             : (-del > where)) {
  804.             (void) putraw('\r');    /* do a CR */
  805.             CursorH = 0;
  806.             goto mc_again;    /* and try again */
  807.         }
  808.         for (i = 0; i < -del; i++)
  809.             (void) putraw('\b');
  810.         }
  811.     }
  812.     }
  813.     CursorH = where;        /* now where is here */
  814. }
  815.  
  816. void
  817. so_write(cp, n)
  818.     register Char *cp;
  819.     register int n;
  820. {
  821.     if (n <= 0)
  822.     return;            /* catch bugs */
  823.  
  824.     if (n > (TermH + 1)) {
  825. #ifdef DEBUG_SCREEN
  826.     xprintf("so_write: n is riduculous: %d\r\n", n);
  827.     flush();
  828. #endif /* DEBUG_SCREEN */
  829.     return;
  830.     }
  831.  
  832.     do {
  833.     if (*cp & LITERAL) {
  834.         extern Char *litptr[];
  835.         Char   *d;
  836.  
  837. #ifdef DEBUG_LITERAL
  838.         xprintf("so: litnum %d, litptr %x\r\n",
  839.             *cp & CHAR, litptr[*cp & CHAR]);
  840. #endif /* DEBUG_LITERAL */
  841.         for (d = litptr[*cp++ & CHAR]; *d & LITERAL; d++)
  842.         (void) putraw(*d & CHAR);
  843.         (void) putraw(*d);
  844.  
  845.     }
  846.     else
  847.         (void) putraw(*cp++);
  848.     CursorH++;
  849.     } while (--n);
  850. }
  851.  
  852.  
  853. void
  854. DeleteChars(num)        /* deletes <num> characters */
  855.     int     num;
  856. {
  857.     if (num <= 0)
  858.     return;
  859.  
  860.     if (!T_CanDel) {
  861. #ifdef DEBUG_EDIT
  862.     xprintf("   ERROR: cannot delete   \n");
  863. #endif /* DEBUG_EDIT */
  864.     flush();
  865.     return;
  866.     }
  867.  
  868.     if (num > TermH) {
  869. #ifdef DEBUG_SCREEN
  870.     xprintf("DeleteChars: num is riduculous: %d\r\n", num);
  871.     flush();
  872. #endif /* DEBUG_SCREEN */
  873.     return;
  874.     }
  875.  
  876.     if (GoodStr(T_DC))        /* if I have multiple delete */
  877.     if ((num > 1) || !GoodStr(T_dc)) {    /* if dc would be more expen. */
  878.         (void) tputs(tgoto(Str(T_DC), num, num), num, putpure);
  879.         return;
  880.     }
  881.  
  882.     if (GoodStr(T_dm))        /* if I have delete mode */
  883.     (void) tputs(Str(T_dm), 1, putpure);
  884.  
  885.     if (GoodStr(T_dc))        /* else do one at a time */
  886.     while (num--)
  887.         (void) tputs(Str(T_dc), 1, putpure);
  888.  
  889.     if (GoodStr(T_ed))        /* if I have delete mode */
  890.     (void) tputs(Str(T_ed), 1, putpure);
  891. }
  892.  
  893. void
  894. Insert_write(cp, num)        /* Puts terminal in insert character mode, */
  895.     register Char *cp;
  896.     register int num;        /* or inserts num characters in the line */
  897. {
  898.     if (num <= 0)
  899.     return;
  900.     if (!T_CanIns) {
  901. #ifdef DEBUG_EDIT
  902.     xprintf("   ERROR: cannot insert   \n");
  903. #endif /* DEBUG_EDIT */
  904.     flush();
  905.     return;
  906.     }
  907.  
  908.     if (num > TermH) {
  909. #ifdef DEBUG_SCREEN
  910.     xprintf("StartInsert: num is riduculous: %d\r\n", num);
  911.     flush();
  912. #endif /* DEBUG_SCREEN */
  913.     return;
  914.     }
  915.  
  916.     if (GoodStr(T_IC))        /* if I have multiple insert */
  917.     if ((num > 1) || !GoodStr(T_ic)) {    /* if ic would be more expen. */
  918.         (void) tputs(tgoto(Str(T_IC), num, num), num, putpure);
  919.         so_write(cp, num);    /* this updates CursorH */
  920.         return;
  921.     }
  922.  
  923.     if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */
  924.     (void) tputs(Str(T_im), 1, putpure);
  925.  
  926.     CursorH += num;
  927.     do 
  928.         (void) putraw(*cp++);
  929.     while (--num);
  930.  
  931.     if (GoodStr(T_ip))    /* have to make num chars insert */
  932.         (void) tputs(Str(T_ip), 1, putpure);
  933.  
  934.     (void) tputs(Str(T_ei), 1, putpure);
  935.     return;
  936.     }
  937.  
  938.     do {
  939.     if (GoodStr(T_ic))    /* have to make num chars insert */
  940.         (void) tputs(Str(T_ic), 1, putpure);    /* insert a char */
  941.  
  942.     (void) putraw(*cp++);
  943.  
  944.     CursorH++;
  945.  
  946.     if (GoodStr(T_ip))    /* have to make num chars insert */
  947.         (void) tputs(Str(T_ip), 1, putpure);/* pad the inserted char */
  948.  
  949.     } while (--num);
  950.  
  951. }
  952.  
  953. void
  954. ClearEOL(num)            /* clear to end of line.  There are num */
  955.     int     num;        /* characters to clear */
  956. {
  957.     register int i;
  958.  
  959.     if (T_CanCEOL && GoodStr(T_ce))
  960.     (void) tputs(Str(T_ce), 1, putpure);
  961.     else {
  962.     for (i = 0; i < num; i++)
  963.         (void) putraw(' ');
  964.     CursorH += num;        /* have written num spaces */
  965.     }
  966. }
  967.  
  968. void
  969. ClearScreen()
  970. {                /* clear the whole screen and home */
  971.     if (GoodStr(T_cl))
  972.     /* send the clear screen code */
  973.     (void) tputs(Str(T_cl), Val(T_li), putpure);
  974.     else if (GoodStr(T_ho) && GoodStr(T_cd)) {
  975.     (void) tputs(Str(T_ho), Val(T_li), putpure);    /* home */
  976.     /* clear to bottom of screen */
  977.     (void) tputs(Str(T_cd), Val(T_li), putpure);
  978.     }
  979.     else {
  980.     (void) putraw('\r');
  981.     (void) putraw('\n');
  982.     }
  983. }
  984.  
  985. void
  986. Beep()
  987. {                /* produce a sound */
  988.     beep_cmd ();
  989.     if (adrof(STRnobeep))
  990.     return;
  991.  
  992.     if (GoodStr(T_vb) && adrof(STRvisiblebell))
  993.     (void) tputs(Str(T_vb), 1, putpure);    /* visible bell */
  994.     else if (GoodStr(T_bl))
  995.     /* what termcap says we should use */
  996.     (void) tputs(Str(T_bl), 1, putpure);
  997.     else
  998.     (void) putraw('\007');    /* an ASCII bell; ^G */
  999. }
  1000.  
  1001. void
  1002. ClearToBottom()
  1003. {                /* clear to the bottom of the screen */
  1004.     if (GoodStr(T_cd))
  1005.     (void) tputs(Str(T_cd), Val(T_li), putpure);
  1006.     else if (GoodStr(T_ce))
  1007.     (void) tputs(Str(T_ce), Val(T_li), putpure);
  1008. }
  1009.  
  1010. void
  1011. GetTermCaps()
  1012. {                /* read in the needed terminal capabilites */
  1013.     register int i;
  1014.     char   *ptr;
  1015.     char    buf[TC_BUFSIZ];
  1016.     static char bp[TC_BUFSIZ];
  1017.     char   *area;
  1018.     extern char *getenv();
  1019.     struct termcapstr *t;
  1020.  
  1021.  
  1022. #ifdef SIG_WINDOW
  1023. # ifdef BSDSIGS
  1024.     sigmask_t omask;
  1025. # endif /* BSDSIGS */
  1026.     int     lins, cols;
  1027.  
  1028.     /* don't want to confuse things here */
  1029. # ifdef BSDSIGS
  1030.     omask = sigblock(sigmask(SIG_WINDOW)) & ~sigmask(SIG_WINDOW);
  1031. # else /* BSDSIGS */
  1032.     (void) sighold(SIG_WINDOW);
  1033. # endif /* BSDSIGS */
  1034. #endif /* SIG_WINDOW */
  1035.     area = buf;
  1036.  
  1037.     GotTermCaps = 1;
  1038.  
  1039.     setname("gettermcaps");
  1040.     ptr = getenv("TERM");
  1041.  
  1042. #ifdef apollo
  1043.     /*
  1044.      * If we are on a pad, we pretend that we are dumb. Otherwise the termcap
  1045.      * library will put us in a weird screen mode, thinking that we are going
  1046.      * to use curses
  1047.      */
  1048.     if (isapad())
  1049.     ptr = "dumb";
  1050. #endif /* apollo */
  1051.  
  1052.     if (!ptr || !ptr[0])
  1053.     ptr = "dumb";
  1054.  
  1055.     setzero(bp, TC_BUFSIZ);
  1056.  
  1057.     i = tgetent(bp, ptr);
  1058.     if (i <= 0) {
  1059.     if (i == -1) {
  1060. #if (SVID == 0) || defined(IRIS3D)
  1061.         xprintf("tcsh: Cannot open /etc/termcap.\n");
  1062.     }
  1063.     else if (i == 0) {
  1064. #endif /* SVID */
  1065.         xprintf("tcsh: No entry for terminal type \"%s\"\n",
  1066.             getenv("TERM"));
  1067.     }
  1068.     xprintf("tcsh: using dumb terminal settings.\n");
  1069.     Val(T_co) = 80;        /* do a dumb terminal */
  1070.     Val(T_pt) = Val(T_km) = Val(T_li) = 0;
  1071.     for (t = tstr; t->name != NULL; t++)
  1072.         TCalloc(t, NULL);
  1073.     }
  1074.     else {
  1075.     /* Can we tab */
  1076.     Val(T_pt) = tgetflag("pt") && !tgetflag("xt");
  1077.     /* do we have a meta? */
  1078.     Val(T_km) = (tgetflag("km") || tgetflag("MT"));
  1079.     Val(T_co) = tgetnum("co");
  1080.     Val(T_li) = tgetnum("li");
  1081.     for (t = tstr; t->name != NULL; t++)
  1082.         TCalloc(t, tgetstr(t->name, &area));
  1083.     }
  1084.     if (Val(T_co) < 2)
  1085.     Val(T_co) = 80;        /* just in case */
  1086.     if (Val(T_li) < 1)
  1087.     Val(T_li) = 24;
  1088.  
  1089.     T_Cols = Val(T_co);
  1090.     T_Lines = Val(T_li);
  1091.     if (T_Tabs)
  1092.     T_Tabs = Val(T_pt);
  1093.     T_HasMeta = Val(T_km);
  1094.     T_CanCEOL = GoodStr(T_ce);
  1095.     T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
  1096.     T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
  1097.     T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
  1098.     if (GoodStr(T_me) && GoodStr(T_ue))
  1099.     me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
  1100.     else
  1101.     me_all = 0;
  1102.     if (GoodStr(T_me) && GoodStr(T_se))
  1103.     me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
  1104.  
  1105.  
  1106. #ifdef DEBUG_SCREEN
  1107.     if (!T_CanUP) {
  1108.     xprintf("tcsh: WARNING: Your terminal cannot move up.\n");
  1109.     xprintf("Editing may be odd for long lines.\n");
  1110.     }
  1111.     if (!T_CanCEOL)
  1112.     xprintf("no clear EOL capability.\n");
  1113.     if (!T_CanDel)
  1114.     xprintf("no delete char capability.\n");
  1115.     if (!T_CanIns)
  1116.     xprintf("no insert char capability.\n");
  1117. #endif /* DEBUG_SCREEN */
  1118.  
  1119.  
  1120.  
  1121. #ifdef SIG_WINDOW
  1122.     (void) GetSize(&lins, &cols);    /* get the correct window size */
  1123.     ChangeSize(lins, cols);
  1124.  
  1125. # ifdef BSDSIGS
  1126.     (void) sigsetmask(omask);    /* can change it again */
  1127. # else /* BSDSIGS */
  1128.     (void) sigrelse(SIG_WINDOW);
  1129. # endif /* BSDSIGS */
  1130. #else /* SIG_WINDOW */
  1131.     ChangeSize(Val(T_li), Val(T_co));
  1132. #endif /* SIG_WINDOW */
  1133.  
  1134.     BindArrowKeys();
  1135. }
  1136.  
  1137. #ifdef SIG_WINDOW
  1138. /* GetSize():
  1139.  *    Return the new window size in lines and cols, and
  1140.  *    true if the size was changed. This can fail if SHIN
  1141.  *    is not a tty, but it will work in most cases.
  1142.  */
  1143. int
  1144. GetSize(lins, cols)
  1145.     int    *lins, *cols;
  1146. {
  1147.     *cols = Val(T_co);
  1148.     *lins = Val(T_li);
  1149.  
  1150. #ifdef TIOCGWINSZ
  1151. # ifndef lint
  1152.     {
  1153.     struct winsize ws;    /* from 4.3 */
  1154.  
  1155.     if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) {
  1156.         if (ws.ws_col)
  1157.         *cols = ws.ws_col;
  1158.         if (ws.ws_row)
  1159.         *lins = ws.ws_row;
  1160.     }
  1161.     }
  1162. # endif /* !lint */
  1163. #else /* TIOCGWINSZ */
  1164. # ifdef TIOCGSIZE
  1165.     {
  1166.     struct ttysize ts;    /* from Sun */
  1167.  
  1168.     if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) {
  1169.         if (ts.ts_cols)
  1170.         *cols = ts.ts_cols;
  1171.         if (ts.ts_lines)
  1172.         *lins = ts.ts_lines;
  1173.     }
  1174.     }
  1175. # endif /* TIOCGSIZE */
  1176. #endif /* TIOCGWINSZ */
  1177.  
  1178.     return (Val(T_co) != *cols || Val(T_li) != *lins);
  1179. }
  1180.  
  1181. #endif /* SIGWINDOW */
  1182.  
  1183. void
  1184. ChangeSize(lins, cols)
  1185.     int     lins, cols;
  1186. {
  1187.     /*
  1188.      * Just in case
  1189.      */
  1190.     Val(T_co) = (cols < 2) ? 80 : cols;
  1191.     Val(T_li) = (lins < 1) ? 24 : lins;
  1192.  
  1193. #ifdef SIG_WINDOW
  1194.     /*
  1195.      * We want to affect the environment only when we have a valid
  1196.      * setup, not when we get bad settings. Consider the following scenario:
  1197.      * We just logged in, and we have not initialized the editor yet.
  1198.      * We reset termcap with tset, and not $TERMCAP has the right
  1199.      * terminal size. But since the editor is not initialized yet, and
  1200.      * the kernel's notion of the terminal size might be wrong we arrive
  1201.      * here with lines = columns = 0. If we reset the environment we lose
  1202.      * our only chance to get the window size right.
  1203.      */
  1204.     if (Val(T_co) == cols && Val(T_li) == lins) {
  1205.     Char    buf[10];
  1206.     char   *tptr;
  1207.  
  1208.     if (getenv("COLUMNS")) {
  1209.         Itoa(Val(T_co), buf);
  1210.         Setenv(STRCOLUMNS, buf);
  1211.     }
  1212.  
  1213.     if (getenv("LINES")) {
  1214.         Itoa(Val(T_li), buf);
  1215.         Setenv(STRLINES, buf);
  1216.     }
  1217.  
  1218.     if (tptr = getenv("TERMCAP")) {
  1219.         Char    termcap[1024], backup[1024], *ptr;
  1220.         int     i;
  1221.  
  1222.         ptr = str2short(tptr);
  1223.         (void) Strncpy(termcap, ptr, 1024);
  1224.         termcap[1023] = '\0';
  1225.  
  1226.         /* update termcap string; first do columns */
  1227.         buf[0] = 'c';
  1228.         buf[1] = 'o';
  1229.         buf[2] = '#';
  1230.         buf[3] = '\0';
  1231.         if ((ptr = Strstr(termcap, buf)) == NULL) {
  1232.         (void) Strcpy(backup, termcap);
  1233.         }
  1234.         else {
  1235.         i = ptr - termcap + Strlen(buf);
  1236.         (void) Strncpy(backup, termcap, i);
  1237.         backup[i] = '\0';
  1238.         Itoa(Val(T_co), buf);
  1239.         (void) Strcat(backup + i, buf);
  1240.         ptr = Strchr(ptr, ':');
  1241.         (void) Strcat(backup, ptr);
  1242.         }
  1243.  
  1244.         /* now do lines */
  1245.         buf[0] = 'l';
  1246.         buf[1] = 'i';
  1247.         buf[2] = '#';
  1248.         buf[3] = '\0';
  1249.         if ((ptr = Strstr(backup, buf)) == NULL) {
  1250.         (void) Strcpy(termcap, backup);
  1251.         }
  1252.         else {
  1253.         i = ptr - backup + Strlen(buf);
  1254.         (void) Strncpy(termcap, backup, i);
  1255.         termcap[i] = '\0';
  1256.         Itoa(Val(T_li), buf);
  1257.         (void) Strcat(termcap, buf);
  1258.         ptr = Strchr(ptr, ':');
  1259.         (void) Strcat(termcap, ptr);
  1260.         }
  1261.         Setenv(STRTERMCAP, termcap);
  1262.     }
  1263.     }
  1264. #endif /* SIG_WINDOW */
  1265.  
  1266.     ReBufferDisplay();        /* re-make display buffers */
  1267.     ClearDisp();
  1268. }
  1269.